package mapEditor.interactor;

import debug.*;
	
import mapEditor.MapEditor;
import mapEditor.map.MapCanvas;
import mapEditor.map.ObjectModel;
import mapEditor.obj.DrawObject;
import mapEditor.utils.MapLocation;
import mapEditor.utils.Util;

import java.awt.Graphics2D;
import java.awt.Cursor;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.ImageObserver;

import javax.swing.JOptionPane;

// ********************************************************************
// *** CLASS: Interactor
// ********************************************************************
public abstract class Interactor implements KeyListener,MouseListener,MouseMotionListener
{ private static final String TAG="mapEditor.interactor.Interactor";
//  private static final boolean VERBOSE=true;
  private static final boolean DEBUG=true;

  public static final int MEASURE=0;   // Mouse-mode: Measuring Distance by pointing (mouse down) and dragging a rectangle.
  public static final int EDIT=1;      // Mouse-mode: Editing.
  public static final int DRAW_LINE=2; // Mouse-mode: Draw a Line by pointing (mouse down) and dragging.
  public static final int DRAW_POLYGON=3; // Mouse-mode: Draw a Polygon by repetive pointing (mouse click).
  public static final int DRAW_ELLIPSE=4; // Mouse-mode: Draw a ...
  public static final int DRAW_PARALLELOGRAM=5; // Mouse-mode: Draw a ...
  public static final int DRAW_PATH=6; // Mouse-mode: Draw a ...
  public static final int DRAW_TEXT=7; // Mouse-mode: Draw a ...
  public abstract String getMouseModeMnemonic();
  
  protected MapCanvas xmapCanvas;
  protected ObjectModel objectModel;

  private int mouseMode; // The current mouse functional mode.
  protected MapLocation mouseStart,mouseCurrent;


  // ******************************************************************
  // *** CONSTRUCTOR: Interactor
  // ******************************************************************
  public Interactor(MapCanvas mapCanvas,int mouseMode)
  { this.xmapCanvas=mapCanvas;
    this.objectModel=mapCanvas.getObjectModel();
    this.mouseMode=mouseMode;
    this.mouseCurrent=MapLocation.newPixelPoint(mapCanvas.getObjectModel(),0,0);
  }
    
  // ******************************************************************
  // *** METHOD: getMouseMode
  // ******************************************************************
  public int getMouseMode()
  { return(mouseMode); }

  // ******************************************************************
  // *** METHOD: paintMouseEffect
  // ******************************************************************
  public abstract void paintMouseEffect(Graphics2D g,ImageObserver imageObserver);


  public void measurementDone(MapLocation loc1,MapLocation loc2)
  { double dist=Util.round(loc1.getDistanceInMeter(loc2),100);
    if(dist>0.1) JOptionPane.showMessageDialog(null,"DISTANCE: "+dist+" meter");
  }

  public void drawObjectDone(DrawObject obj,String id)
  { int result=JOptionPane.showConfirmDialog(null,"DRAW "+id+": DONE\n Edit Attributes ?"
      		  ,"Add "+obj.getClassName(),JOptionPane.YES_NO_OPTION);
    objectModel.addChild(obj);
    if(result==JOptionPane.YES_OPTION) obj.edit();
  }

  
  // ******************************************************************
  // *** METHOD: keyTyped
  // ******************************************************************
  // Invoked when a key has been typed (key press is followed by a key release).
  public void keyTyped(KeyEvent e) {}

  // ******************************************************************
  // *** METHOD: keyPressed
  // ******************************************************************
  // Invoked when a key has been pressed.
  public void keyPressed(KeyEvent e) {}

  // ******************************************************************
  // *** METHOD: keyReleased
  // ******************************************************************
  // Invoked when a key has been released.
  public void keyReleased(KeyEvent e) {}

  // ******************************************************************
  // *** METHOD: mouseDragged
  // ******************************************************************
  // Invoked when a mouse button is pressed and then dragged.
  public void mouseDragged(MouseEvent e)
  { mouseCurrent.setX(e.getX());
    mouseCurrent.setY(e.getY());
	MapEditor.getStatusLine().setMousePosition(mouseCurrent);
    mouseDragged();
  }
  protected abstract void mouseDragged();


  // ******************************************************************
  // *** METHOD: mouseMoved
  // ******************************************************************
  // Invoked when the mouse has been moved (with no buttons down).
  private Cursor pointCursor=Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  private Cursor crossHairCursor=Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
  private Cursor handCursor=Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
  public void mouseMoved(MouseEvent e)
  { mouseCurrent.setX(e.getX());
    mouseCurrent.setY(e.getY());
	MapEditor.getStatusLine().setMousePosition(mouseCurrent);
	Cursor oldCursor=xmapCanvas.getCursor();
//	Cursor newCursor=(mapCanvas.withinPointMark()!=null)?crossHairCursor:pointCursor;
	Cursor newCursor=pointCursor;
	String newDescription="";
	if(xmapCanvas.getPointMark(mouseCurrent)!=null) newCursor=crossHairCursor;
	else
	{ DrawObject obj=xmapCanvas.getObject(mouseCurrent);
	  if(obj!=null) { newCursor=handCursor; newDescription=obj.getIdent(); }
	}
	if(newCursor!=oldCursor)
    { xmapCanvas.setCursor(newCursor);
      xmapCanvas.repaint();
    }
    MapEditor.getStatusLine().setDescription(newDescription);
    mouseMoved();
  }
  protected abstract void mouseMoved();
  
  // ******************************************************************
  // *** METHOD: mouseEntered
  // ******************************************************************
  // Invoked when the mouse enters a component.
  public void mouseEntered(MouseEvent e) {}

  // ******************************************************************
  // *** METHOD: mouseExited
  // ******************************************************************
  // Invoked when the mouse exits a component.
  public void mouseExited(MouseEvent e) {}

  // ******************************************************************
  // *** METHOD: mouseClicked
  // ******************************************************************
  // Invoked when the mouse has been clicked on a component.
  public void mouseClicked(MouseEvent e) {}

  // ******************************************************************
  // *** METHOD: mousePressed
  // ******************************************************************
  // Invoked when a mouse button has been pressed.
  public void mousePressed(MouseEvent e)
  { MapLocation p=MapLocation.newPixelPoint(objectModel,e.getX(),e.getY());
    if(DEBUG) Log.d(TAG,"mousePressed: at "+p);
	int flg=e.getModifiers();
    if((flg& InputEvent.BUTTON1_MASK)!=0)
         mouseLeftPressed(p);
    else mouseRightPressed(p);
  }
  protected abstract void mouseLeftPressed(MapLocation p);
  protected abstract void mouseRightPressed(MapLocation p);

  // ******************************************************************
  // *** METHOD: mouseReleased
  // ******************************************************************
  // Invoked when a mouse button has been released.
  public void mouseReleased(MouseEvent e)
  { MapLocation p=MapLocation.newPixelPoint(objectModel,e.getX(),e.getY());
    if(DEBUG) Log.d(TAG,"mouseReleased: at "+p);
    int flg=e.getModifiers();
    if((flg& InputEvent.BUTTON1_MASK)!=0) mouseLeftReleased(p);
    else mouseRightReleased(p);
  }
  protected abstract void mouseLeftReleased(MapLocation p);
  protected abstract void mouseRightReleased(MapLocation p);
  
}